
#pragma once

#ifndef _fmbLog
#define _fmbLog

#include "fmbErr.h"
#include "fmbMutex.h"
#include "fmbList.h"
#include "fmbSingleton.h"

#ifdef _ANDROID
#include <stdio.h>
#include <stdarg.h>
#else
#include <cstdio>
#include <cstdarg>
#endif

namespace fm {
  namespace base {

class LogSink;

/// <summary>
///   Class for logging. Implementation as singleton.
/// </summary>
class Log {

  friend class Singleton<Log>;

  static const int MESSAGE_BUFFER_SIZE = 2048;

  static Mutex m_mutex;
  static Log *m_instance;

  typedef List<LogSink*> SinkList;
  SinkList m_sinkList;

  typedef ObjectLevelLockingPolicy::Lock Lock;
  ObjectLevelLockingPolicy m_lockingPolicy;
  char m_msgBuf[MESSAGE_BUFFER_SIZE];


  Log();
  ~Log();

public:
    enum Level {
    INFO = 0,
    WARN = 1,
    ERR = 2,
    DEBUG = 3,
    TRACE = 4
  };

private:
  // prevent misuse
  inline Log(const Log &source) {};
  inline Log &operator=(const Log &source) {};

private:
  void msg(Level level, const char *pattern, va_list args);

public:

  static void addSink(LogSink *sink);

  static void info(const char *pattern, ...);
  static void warn(const char *pattern, ...);
  static void err(const char *pattern, ...);
  static void debug(const char *pattern, ...);
  static void trace(const char *pattern, ...);
};

class LogSink {
  friend class Log;
  virtual void msg(Log::Level level, const char *msg) = 0;
public:
  virtual ~LogSink();
};

class LogConsoleSink : public LogSink {
  virtual void msg(Log::Level level, const char *msg);
public:
  virtual ~LogConsoleSink();
};

class LogJNISink : public LogSink {
  virtual void msg(Log::Level level, const char *msg);
public:
  virtual ~LogJNISink();
};

  // end of namespace fm::base
  }
// end of namespace fm
}

#endif
